Logical Architecture
The design of a typical OO system is based on several architectural layers, such as a UI layer, an application logic (or "domain") layer, and so forth. UML package diagrams may illustrate the logical architecture as part of the Design Model, and also be summarized as a view in the Software Architecture Document. The prime input is the architectural forces captured in the Supplementary Specificaiton. The logical architecture is the large-scale organization of the software classes into packages (or namespaces), subsystems, and layers. It's called the //logical// architecture because there's no decision about how these elements are deployed across different operating system processes or across physical computers in a network (these latter decisions are part of the //deployment architecture//). A layer is a very coarse-grained grouping of classes, packages, or subsystems that has cohesive responsibility for a major aspect of the system. Also, layers are organized such that "higher" layers (such as the UI layer) call upon services of "lower" layers, but not normally vice versa. Typical layers in an OO system include: * **User interface** * **Appication Logic and Domain Objects:** Software objects representing domain concepts that fulfill application requirements. * **Technical Services:** General purpose objects and subsystems that provide supporting technical services, such as interfacing with a database or error logging. These services are usually application-independent and reusable across several systems. In a //strict layered architecture//, a layer only calls upon the services of the layer directly below it. This design is common in network protocol stacks, but not in information systems, which usually have a //relaxed layered architecture//, in which a higher layer calls upon several lower layers. For example, the UI layer may call upon its directly subordinate application logic layer, and also upon elements of a lower technical service layer, for logging and so forth. Package Diagrams UML package diagrams are often used to illustrate the logical architecture of a subsystem. They provide a way to group elements, e.g. classes, other packages, use cases, and so on. The package name may be placed on the tab if the package shows inner members, or on the main folder, if not. It is common to want to show dependency between packages to show the large-scale coupling in the system. The UML //dependency line// is used for this, a dashed arrow line with the arrow pointing towards the dependend-on package. A UML package represents a //namespace// so that, e.g. a class, may be defined in two packages. The //fully-qualified name// notation is e.g. java::util::Date. Design with Layers The essential ideas of using layers are simple: * Organize the large-scale logical structure of a system into discrete layers of distinct, related responsibilities, with a clean, cohesive separation of concerns such that the "lower" layers are low-level and general services, and the higher layers are more application specific. * Collaboration and coupling is from higher to lower layers. Lower-to-higher layer coupling is avoided. This idea is described as the //Layers pattern// and produces a //layered architecture//. It has been applied and written about so often as a pattern that the book Pattern Almanac lists over 100 patterns that are variants of or related to the Layers pattern. Benefits of using layers: * In general, there is a separation of concerns, a separation of high from low-level services, and of application-specific from general services. This reduces coupling and dependencies, improves cohesion, increases reuse potential, and increase clarity. * Related complexity is encapsulated and decomposable. * Some layers can be replaced with new implementations. This is generally not possible for lower-level Technical Service or Foundation layers, but may be possible for UI, Application, and Domain layers. * Lower layers contain reusable functions. * Some layers (primarily the Domain and Technical Services) can be distributed. * Development by teams is aided because of the logical segmentation. Typical layers The order of the following layers reflects the range of applicability. **UI** (Presentation, View) * GUI windows * Reports * Speech interface * HTML, XML, XSLT, JSP, Javascript, ... **Application** (Workflow, Process, Mediation, App Controller) * Handles presentation layer requests * Workflow * Session state * Window/page transitions * Consolidation/transformation of disparate * Date for presentation **Domain** (Business, Application Logic, Model) * Handles application layer requests * Implementation of domain rules * Domain services **Business Infrastructure** (Low-level Business Services) * Very general low-level business services used in many business domains * CurrencyConverter **Technical Services** (Technical Infrastructure, High-level Technical Services) * (relatively) High-level technical services and frameworks * Persistence, Security **Foundation** (Core Services, Base Services, Low-level Technical Services/Infrastructure) * Low-level technical services, utilities, and frameworks * Data structures, threads, math, file, DB, and network I/O Most systems rely on external resources or services, such as a MySQL inventory database and a Novell LDAP naming and directory services. These are //physical// implementation components, not a layer in the logical architecture. Showing external resources such as a particular database in a layer "below" the Foundation layer mixes up the logical view and the deployment view of the architecture. Rather, in terms of the logical architecture and its layers, access to a particular set of persistent data can be viewed as a sub-domain of the Domain Layer - the Inventory sub-domain. And the general services that provide access to databases may be viewed as a Technical Service partition - the Persistence service. Separation of Concerns The responsibilities of the objects in a layer should be strongly related to each other and should not be mixed with responsibilities of other layers. E.g. objects in the UI layer should focus on UI work, such as creating windows and widgets, capturing mouse and keyboard events, and so forth. Objects in the application logic layer should focus on application logic, such as calculating a sales total or texes, or moving a piece on a game board. Maintain a clear //separation of concerns// and //high cohesion//. These are basic architectural principles. Mapping UML Packages to Code // --- UI Layer com.company.netxgen.ui.swing com.mycompany.netxgen.ui.web // --- DOMAIN Layer // packages specific to the NexGen project com.mycompany.nextgen.domain.sales com.mycompany.nextgen.domain.payments // --- TECHNICAL SERVICES Layer // our home-grown persistence (database) access layer com.mycompany.service.persistence // third party org.apache.log4j org.apache.soap.rpc // --- FOUNDATION Layer // foundation packages that our team creates com.mycompany.util Notice that, to support cross-project reuse, avoid using a specific application qualifier ("nextgen") in the package names unless necessary. The UI packages are related to the NextGen POS application, so they are qualified with the application name com.mycompany.nextgen.ui.*. But the utilities we write could be shared across many projects, hence the package name com.mycompany.utils. Domain Layer vs. Domain Model There's a relationship between the domain model and the domain layer. Look to the domain model (which is a visualization of noteworthy domain concepts) for inspiration for the names of classes in the domain layer. The domain layer is part of the software and the domain model is part of the conceptual-perspective analysis - they aren't the same thing. But by creating a domain layer with inspiration from the domain model, we achieve a //lower representational gap// between the real-world domain and our software design. Model-View Separation Principle The Model-View Separation Principle has at least two parts: # Don't couple non-UI objects directly to UI objects. Don't let a Sale software object have a reference to a JFrame window object. The windows are related to a particular application, while (ideally) the non-windowing objects may be reused in new applications or attached to a new interface. # Don't put application logic in the UI object methods. UI objects should only initialize UI elements, receive UI events, and delegate requests for application logic on to non-UI objects (such as domain objects). A legitimate relaxation of this principle is the Observer pattern, where the domain objects send messages to UI objects viewed only in terms of an interface such as PropertyListener. Then, the domain objects doesn't know that the UI object is a UI ubject - it doesn't know its concrete window class. It only knows the object as something that implements the PropertyListener interface. Layers vs. SSD and System Operations The SSDs illustrate system operations, but hide the specific UI objects. Nevertheless, normally it will be objects in the UI layer of the system that capture these system operation requests, usually with a rich client GUI or Web page. In a well-designed layered architecture that supports high cohesion and a separation of concerns, the UI layer objects will then delegate the requests from the UI layer onto the domain layer for handling. The key point here: The messages sent from the UI layer to the domain layer will be the messages illsutrated on the SSDs, such as enterItem. References # Craig Larman, "Applying UML and Patterns", Ch.13 Recommended reading # Eric Freeman, Elisabeth Freeman, "Head First Design Patterns" # Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, "Design Patterns - Elements of Reusable Object-Oriented Software" # Martin Fowler , "Analysis Patterns - Reusable Object Models" # Eric Evans, "Domain-Driven Design - Tackling Complexity in the Heart of Software" # Martin Fowler, "Refactoring - Improving the Design of Existing Code" # Martin Fowler, "Patterns of Enterprise Application Architecture" # Kent Beck, "Implementation Patterns" # Joshua Kerievsky, "Refactoring to Patterns" Category:Design